#include "seven_bus.h"
#include "seven_bus_packet.h"
#include "errno.h"
#include "tsrb.h"
#include "thread.h"
#include "string.h"

#define SEVENBUS_MODE_NONE (0)
#define SEVENBUS_MODE_RECV (1)
#define SEVENBUS_MODE_SEND (2)

#define SEVENBUS_TX_MSG_QUEUE_SIZE (4)

typedef struct {
    uint8_t addr;
    char cur_mode;
}seven_bus_state_t;

static seven_bus_state_t _g_bus_state = {0};

static tsrb_t _g_in_buf;
static uint8_t _rx_mem[16];
static char _stack[THREAD_STACKSIZE_SMALL];
static msg_t _tx_msg_queue[SEVENBUS_TX_MSG_QUEUE_SIZE];

/**
 * @brief 检测到数据碰撞, 取消发送，并根据消息的优先级设置重试时间
 * 
 * @param arg 
 */
static void _cd_detect(void *arg)
{

}
/**
 * @brief 数据接收函数。
 *          1. 当前模式为接收模式（SEVENBUS_MODE_RECV）时，将数据放入缓冲区中
 *          2. 当前模式为发送模式(SEVENBUS_MODE_SEND)时，判断接收到的数据，是否与发送一致，不一致则说明总线冲突，停止发送
 * 
 * @param arg 
 * @param data 
 */
static void _rx_cb(void *arg, uint8_t data)
{
    //caution: here is in isr, interrupt context

}

/**
 * @brief 总线处理线程
 *  - 如果有数据要发送，发送数据
 *  - 接收数据并解析
 * 
 * @param arg 
 */
static void * _bus_process(void *arg)
{
    msg_t msg;
    seven_bus_dev_t *dev = (seven_bus_dev_t*)arg;

    //init msg queue
    msg_init_queue(_tx_msg_queue, SEVENBUS_TX_MSG_QUEUE_SIZE);

    seven_bus_pkt_buff_init();

    // resend current pkt
    // try to recv msg 
    if (msg_try_receive(&msg) == 1) {
        //recv success
    }

    //parse rx buffer
    if (!tsrb_empty(&_g_in_buf)) {
        seven_bus_pkt_buff_rx(dev, tsrb_get_one(&_g_in_buf));
    }

    return NULL;
}

int seven_bus_init(seven_bus_dev_t *dev, uint8_t priority)
{
    if ((NULL == dev) || (!gpio_is_valid(dev->param.cd_pin))) {
        return -EINVAL;
    }

    int ret = 0;

    memset(&_g_bus_state, 0, sizeof(_g_bus_state));
    _g_bus_state.cur_mode = SEVENBUS_MODE_RECV;
    _g_bus_state.addr = dev->param.bus_addr;

    //init tsrb(thread safe ring buffer) for rx
    tsrb_init(&_g_in_buf, _rx_mem, sizeof(_rx_mem));
    //init uart for tx & rx
    ret = uart_init(dev->param.uart, dev->param.baudrate, _rx_cb, dev);
    if (ret) {
        //init uart failed
        return ret;
    }
    //init cd gpio pin intr
    
    ret = gpio_init_int(dev->param.cd_pin, GPIO_IN_PD, GPIO_RISING, _cd_detect, dev);
    if (ret) {
        //init gpio failed
        uart_poweroff(dev->param.uart);
        return ret;
    }

    //create thread
    thread_create(_stack, sizeof(_stack), priority, THREAD_CREATE_STACKTEST, _bus_process, dev, "sevenbus");


    return ret;
}

int sevenbus_send(uint8_t id, uint8_t len, uint8_t *data)
{
    return 0;
}
